// free tools for java
Obfuscator
T o o l s
-Obfuscator
-Installer
-Assembler
-Links
-Old tools
  Hashjava contains a java library and two applications which obfuscate and shrink your class files. Hashjava runs on Java 1.0.2 and 1.1 compliant VMs, and handles Java 1.0.2 and 1.1 class files.

Using hashjava on your applets does not make it safe from decompilation, it just takes a little longer to make sense of it. Please use version 0.8 released on September 4, 1997, which fixes some bugs handling inner classes and handles code coverage attributes inserted by the JDK compiler.

Download!
  • Download a self extracting class file. Save this file as hjinstall.class and run "java hjinstall". If you have problems installing this program with its GUI, try installing it in console mode, with "java hjinstall -o path/to/destination".

  contents
 
  applet obfuscator
  Hashjava includes an example application which obfuscates applets. If the installation in the previous step was successful, you should find a script in the distribution as bin/HashApplet. If for any reason this file was not created, the application main class is sbktech.tools.hashjava.hashpplet.Main.

The wizard will guide you through the steps to obfuscate your applet. The idea is to feed it a URL to an html file with your original applet, and an output directory to write out the obfuscated applet. You can select the types of symbols to obfuscate (class names, method names, field names), how you want to handle debugging symbols (keep, remove or put confusing information in them) or select the obfuscated names (lowercase English alphabets, numbers or all valid java unicode characters.)

Play it safe! Back up your applets before using this application.
Start the application by running
% bin/HashApplet
This will launch a session which you can guide to load, obfuscate and write out applets from an HTML file. If the obfuscation was successful, you will find a copy of the original HTML file and obfuscated bytecode in the output directory.
Watch out for these problems!
  • HashApplet does not detect images or other files that are explicitly loaded by the applet, so you will have to copy such files to make the obfuscated applet work again.
  • Some sequences of html can confuse HashApplet. If HashApplet incorrectly detects no applet tags in the HTML source, try using a simpler HTML file with just a set of applet tags.
  • HashApplet tries to duplicate the original directory structure of applets which use CODEBASE tags, but some combinations can defeat it. In particular, using a CODEBASE with an absolute URL will usually result in an incorrect directory structure.
  • If any classes are shared between applets which haven't been obfuscated at the same time, some applets will be incorrectly obfuscated. Obfuscate all applets at the same time -- create a single dummy html file with references to all your applets and run HashApplet on that file.
  • Stack traces will no longer be available. To preserve stack traces (but lose some obfuscation) retain source file names and line numbers.
  • If your code uses Class.forName(), HashApplet will incorrectly or incompletely obfuscate the bytecode. HashApplet will notify you when obfuscated classes use this call. You should turn off renaming class names, which correctly, but incompletely obfuscates the bytecode. To obfuscate all the bytecode, create a single dummy html file with references to all of your classes called through forName() (even if they don't subclass Applet) and run HashApplet on this file. You should still turn off renaming classes.

  command line obfuscator
  Hashjava also includes a command line obfuscator which uses a configuration file to provide a greater degree of control over what methods and classes get renamed.

Start the command line obfuscator with a configuration file as its only argument.

% bin/Hashjava <path To Configuration File>
The minimum things to include in a configuration file are the root directory (or zip file) of a set of classes to obfuscate, and an output directory to store the obfuscated classes.
ObfuscateRoot("/path/to/original/classes");
OutputDir("/path/to/new/classes");
With just this information, every class recursively found from the original directory will be fully obfuscated. Every method and field that can be renamed will be renamed, and the obfuscated classes will be placed into the new directory.

You can now selectively prevent an entire class, or selected methods or fields, or just the class name from being obfuscated. For instance,
ObfuscateRoot("/path/to/original/classes");
OutputDir("/path/to/new/classes");
ExcludeAll(PUBLIC, "MyMainClass");
will fully obfuscate all classes except MyMainClass. You can refine this further and just keep the class name and the main() method name for MyMainClass with
ObfuscateRoot("/path/to/original/classes");
OutputDir("/path/to/new/classes");
ExcludeClass(PUBLIC, "MyMainClass");
ExcludeMethod(PUBLIC & STATIC,
              "MyMainClass.main");
You can also specify wildcards in the string. Please refer to the example configuration file in the distribution which uses all the directives understood by the batch obfuscator.

  HashApplet and mocha
  Mocha is a popular freely available decompiler.
Mocha's author also provides an obfuscator Crema, which however is not freely available if you want to obfuscate applets. The free version of Crema inserts illegal identifiers in applets which does not pass security checks in many browsers.

Hanpeter, the author of Mocha and Crema has passed away.

By default, HashApplet inserts a few confusing debugging attributes (this does not affect the applet unless it runs under a debugger) which consistently seems to crash mocha. If you change the settings to instead remove all debugging attributes, mocha appears to work again.

Here is mocha output on part of a class from one of the JDK demos before and after using HashApplet.
Mocha before HashApplet
void transform()
{
  if (transformed || nvert <= 0)
    return;
  if (tvert == null || tvert.length < nvert * 3)
    tvert = new int[nvert * 3];
  mat.transform(vert, tvert, nvert);
  transformed = true;
}
After HashApplet (without mocha bomb)
void C()
{
  if (I || E <= 0)
    return;
  if (C == null || C.length < E * 3)
    C = new int[E * 3];
  J.O(A, C, E);
  I = true;
}

  programming with hashjava
  Hashjava is really just a library to fix up references in a set of bytecode files as you alter symbol names in any of them. The hashjava API lets you add a set of classes and examine and alter symbols in them.
Obfuscation works in 3 steps
  1. Add all classes to be kept in sync.
  2. Alter desired symbols in each class.
  3. Write out the altered classes.
The Environment stores information about all the classes. It delegates the reading/writing of classes, and the chore of picking new symbol names to its instantiator.

So to create an Environment, you have to hand it an instance of the BytecodeFactory and the Obfuscator interfaces. You actually have to pass an instance of the Statistics interface as well, which effectively observes the state of the Environment.

The distribution includes Example.java under the hashjava/src directory. This is a small application which demonstrates how to use the library.
Once you create an Environment, obfuscation works in three stages.
  1. Add all the bytecode with the addClass() method. The Environment will automatically add any dependent classes (which are the superclasses or interfaces implemented by the class) using your BytecodeFactory interface. You can optionally ask for all dependencies to be loaded, which means any class referenced in the bytecode will be automatically added.
  2. Obfuscate the bytecode with the obfuscate() method. This calls your Obfuscator interface with every class in the environment. You can use the methods in ClassInfo to examine and alter symbols in each class.
  3. Write out the altered bytecode with the dump() method.

  frequently asked questions
 
I get an OutOfMemoryError running the obfuscator
Edit the scripts and try increasing the size of the virtual machine heap space. For the Sun JDK, use the command line option -mx 80m for example, to use 80 MB of heap space.
How do I obfuscate a netscape IFC applet?
Increase the default heap size, because obfuscating an IFC applet needs a lot of memory. If you write a "typical" IFC applet, it probably uses a Class.forName() call to load the real applet, which needs to be handled properly. One solution is to use a special html file used only for obfuscation, which contains a fake applet tag pointing to the class for your real IFC applet. For example, the original HTML file for the Aquarium demo looks like
<applet code="NetscapeApplet"
  width=640 height=410>
<param name="ApplicationClass"
  value="Aquarium">
</applet>
and the special html file used only for obfuscation looks like
<applet code="NetscapeApplet"
  width=640 height=410>
<param name="ApplicationClass"
  value="Aquarium">
</applet>

<applet code=Aquarium
  width=10 height=10>
</applet>
An alternate solution is to use the command line obfuscator. Here is a sample configuration file, again for the Aquarium demo from the IFC demo.
ObfuscateRoot
  ("/cadmium4/examples/Aquarium");
OutputDir
  ("/tmp/newAquarium");
ExcludeAll
  (ALL, "netscape.*");
ExcludeClass
  (ALL, "NetscapeApplet");
ExcludeClass
  (ALL, "Aquarium");
DontDump
  (ALL, "netscape.*");
How do I change the names chosen by the obfuscator?
If you want to specify an explicit map of original names to obfuscated names, use the LoadMap directive in the configuration file for the command line obfuscator. This reads in an ASCII file where each line is an entry like
ClassName=NewName
ClassName.method=newMethodName
If the batch obfuscator does not find a name for some class or method or field here, it picks a random name, and is guaranteed not to conflict with any name you have used in the LoadMap file.

If you want to specify your own algorithm to map names, write a java class which implements the NameGenerator interface. Specify this class name in any of the ClassNameGenerator, FieldNameGenerator or MethodNameGenerator directives in the configuration file for the batch obfuscator, and it will start using your class to generate names.

Finally, you can use the basic Hashjava programming API to write your own obfuscator. Take a look at the sample programming example for a starting point.

How can I incrementally obfuscate a new set of classes which use a previously obfuscated set of classes?
This is possible only if the API to your previous set of classes has not changed. If you have
  • the unobfuscated version of the previous classes and
  • a "map" of the original to obfuscated names
you can create an obfuscated version of your new classes which will work with the obfuscated version of the previous classes. This works by using a combination of the DumpMap and LoadMap directives in the batch obfuscator.
  1. When you obfuscate the original set of classes, dump the original to new names with the DumpMap directive.
  2. When you obfuscate the new set of classes, load the file generated in Step 1 with the LoadMap directive, and obfuscate it along with the original set of classes. You can prevent hashjava dumping the original classes with an appropriate DontDump directive. Look at the example configuration file for directions on using these directives.
How do I select inner classes from the symbol map or in an ExcludeXXX directive?
Inner classes are named by the JDK 1.1 compiler by appending the innerclass name to the parent scope, separated by a $. Anonymous classes, or classes within a method scope have an integer following the parent scope.

To select an inner class, you must specify the "mangled" name given to it by the JDK 1.1 compiler. For instance, the inner classes in

class Outer {
  class Inner {
    class Nested {
    }
  }
}
are identified by Outer$Inner and Outer$Inner$Nested. Lets say you want to ExcludeClass the class Outer and all its inner classes. Use this directive in the configuration file
ExcludeClass(ALL, "Outer*");
If you want to obfuscate the inner class Nested, but ExcludeClass its outer classes, use
ExcludeClass(ALL, "Outer");
ExcludeClass(ALL, "Outer$Inner");
Note: the name for an inner class is derived, even in the obfuscated code, from the parent scope. For instance, if you have a symbol map entry like
Outer=X
Outer$Inner=Y
Outer$Inner$Nested=Z
the class names become X, X$Y and X$Y$Z and the attributes informing the compiler about the relationships between the inner classes and their parent scope are appropriately updated.
My Serializable classes don't work anymore.
The Java 1.1 serialization mechanism searches for "magic" private methods named readObject and writeObject in your classes. Unless you prevent it, hashjava will obfuscate these names and the serialization won't work properly. Use the batch obfuscator and add these two directives in your configuration file
ExcludeMethod(PRIVATE, "*.readObject");
ExcludeMethod(PRIVATE, "*.writeObject");
I want to send you money for hashjava.
Ok, so this really my frequently fantasized question :-) though "This is great! Why don't you charge money for it?" does come up on occasion.

If you like it enough you would have paid money for a copy, I'll be very happy if you give $10 via the online donation center to the American Red Cross, or any international charity of your choice.

My plans are to keep hashjava freely available under the LGPL, but I do not have the resources to offer paid support. I do fix bug reports as soon as I can, which is generally over a weekend or two.

If you are a tool vendor or software distributor interested in including hashjava with your product, you can freely do so under the terms of the LGPL. Please feel free to contact me for any information or assistance.

  Related resources
  These are some additional resources that might be interesting.
  licensing
  Hashjava is freely distributed with source code under the GNU Library General Public License (LGPL). Code generated by hashjava does not fall under the same license, and you can use your obfuscated code with no restrictions.

Under the LGPL, you can also use hashjava as a library and call its public classes or methods in commercial or non-commercial applications without disclosing your own source code, provided you supply the source code to hashjava, and enable anyone modifying hashjava (without changing its public API) to freely link with your application. The license has the final word in all cases, but feel free to contact me for any clarifications.

 
T o o l s

Obfuscator | Installer | Assembler | Links | Old tools

http://www.sbktech.org/hashjava.html Revised: Tue Sep 9 22:38:50 1997
Copyright (C) 1996 KB Sriram.
Comments, bug reports: kbs@sbktech.org
Found something useful?